const fp = require("fastify-plugin");
const Transaction = require("sequelize").Transaction;

//重要：这是一个fastify的插件
module.exports = fp(async function (fastify, options) {
  //事务参数
  const trsOptions = {
    //默认为空，这里整个read commited级别
    isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED,
    //这是默认值
    type: Transaction.TYPES.DEFERRED,
  };
  //这个plugin的公共事务：直接获取事务（用await）
  //顺便引入一下事务参数
  const trs = await fastify.sequelize.transaction(trsOptions);
  //注册至名称：cardService
  fastify.decorate("cardTest", function () {
    //之前将card的model以“card”注册在了fastify，现在就可以fastify.card()获取到model实例
    const cardModel = fastify.card();
    //引用fastify自己封装的log
    const log = fastify.log;
    //从options中拿出封装在其中的logLevel
    log.level = options.logLevel;

    //修改卡信息，先根据ID查卡，没有就新增
    async function updateWithTransaction(params) {
      //使用自动式事务管理
      return fastify.sequelize.transaction((trans) => {
        //开始实现业务逻辑
        //查卡，查完卡用then()执行下一步
        return (
          cardModel
            //-------------------------👇与之前的findByPk有些不同，后面还带了个参数集合
            //-------------------------👇这里我们引入了transaction参数，指明要使用事务
            //-------------------------👇使用的事务就是由自动式事务管理方法传递下来的“trans”
            .findByPk(params.id, { transaction: trans })
            .then((card) => {
              //判断卡是否为空
              if (card) {
                //根据参数改卡信息----------------👇这里我们也指明事务
                return card.update(params, { transaction: trans });
                //---------------
                //注意这里我们没有指明什么.commit()或者.rollback()发方法来提交/回滚事务
                //---------------
              } else {
                //根据参数新增卡----------------------👇这里我们也指明事务
                return cardModel.create(params, { transaction: trans });
              }
            })
        );
      });
      // .then((result) => {
      //   return { code: 200, msg: "", data: result };
      // })
      // .catch((error) => {
      //   log.error(error);
      //   return { code: 502, msg: error.message, data: error };
      // });
    }

    async function updateWithTransaction2(params) {
      //使用自动式事务管理
      //不then()下去的话用await也可以，但是要用await就得在transaction内的方法前加上acync
      //-----------------------------------------------👇------------
      return fastify.sequelize.transaction(trsOptions, async (trans) => {
        const card = await cardModel.findByPk(params.id);
        if (card) {
          //自动式事务管理直接返回操作
          return card.update(params, { transaction: trans });
        } else {
          //自动式事务管理直接返回操作
          return cardModel.create(params, { transaction: trans });
        }
      });
    }

    async function handleTransaction(params) {
      try {
        //这里我们就不使用一连串的then()，我们使用await
        //先根据ID查卡
        const card = await cardModel.findByPk(params.id, { transaction: trs });

        if (card) {
          //有卡，根据数据升级卡
          await card.update(params, { transaction: trs });
          //*重要：事务提交 */
          await trs.commit();
          //注意：手动提交事务的话就不能return trs.commit()，得返回model
          return card;
        } else {
          //无卡，新建卡
          const newCard = await cardModel.create(params, { transaction: trs });
          //*重要：事务提交 */
          await trs.commit();
          //注意：手动提交事务的话就不能return trs.commit(),得返回model
          return newCard;
        }
      } catch (error) {
        log.error(error);
        //同理，无法返回 trs.rollback()
        await trs.rollback();
        throw error;
      }
    }

    return {
      updateWithTransaction,
      updateWithTransaction2,
      handleTransaction,
    };
  });
});
